package com.fll.protocol;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

/**
 * 通常来说，使用ByteToMessageDocoder这个解码器，
 * 我们要分别解析出报头，长度，体这几个字段。
 * 而使用LengthFieldBasedFrameDecoder，
 * 我们就可以直接接收想要的一部分，相当于在原来的基础上包上了一层，
 * 有了这层之后，我们可以控制我们每次只要读想读的字段，
 * 这对于自定义协议来说十分方便
 * @author fanlei
 * @version 1.0
 * @date 2019年01月25日
 */
public class ProxyMessageDecoder extends LengthFieldBasedFrameDecoder{

    private static final byte HEADER_SIZE = 4;
    private static final int TYPE_SIZE = 1;
    private static final int SERIAL_NUMBER_SIZE = 8;
    private static final int URI_LENGTH_SIZE = 1;




    public ProxyMessageDecoder(int maxFrameLength, int lengthFieldOffset,
                               int lengthFieldLength, int lengthAdjustment,
                               int initialBytesToStrip) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
    }

    /**
     * @param maxFrameLength  帧的最大长度
     * @param lengthFieldOffset length字段偏移的地址
     * @param lengthFieldLength length字段所占的字节长
     * @param lengthAdjustment 修改帧数据长度字段中定义的值，可以为负数 因为有时候我们习惯把头部记入长度,若为负数,则说明要推后多少个字段
     * @param initialBytesToStrip 解析时候跳过多少个长度
     * @param failFast 默认为true，当frame长度超过maxFrameLength时立即报TooLongFrameException异常，为false，读取完整个帧再报异
     */
    public ProxyMessageDecoder(int maxFrameLength, int lengthFieldOffset,
                               int lengthFieldLength, int lengthAdjustment,
                               int initialBytesToStrip, boolean failFast) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
    }


    @Override
    protected ProxyMessage decode(ChannelHandlerContext ctx, ByteBuf in2) throws Exception {
        //在这里调用父类的方法,实现指得到想要的部分,我在这里全部都要,也可以只要body部分
        ByteBuf in = (ByteBuf)super.decode(ctx, in2);

        if (in == null) {
            return null;
        } else if (in.readableBytes() < 4) {
//            throw new Exception("字节数不足");
            return null;
        } else {
            //读取length字段
            int frameLength = in.readInt();//4个字节
            if (in.readableBytes() < frameLength) {
                //标记的长度不符合实际长度
                return null;
            } else {
                ProxyMessage proxyMessage = new ProxyMessage();
                //读取type
                byte type = in.readByte();
                //读取SerialNumber
                long sn = in.readLong();
                proxyMessage.setSerialNumber(sn);
                proxyMessage.setType(type);
                //读取uri长度
                byte uriLength = in.readByte();
                byte[] uriBytes = new byte[uriLength];
                in.readBytes(uriBytes);
                proxyMessage.setUri(new String(uriBytes));
                //读取剩余的data
                byte[] data = new byte[frameLength - 1 - 8 - 1 - uriLength];
                in.readBytes(data);
                proxyMessage.setData(data);
                in.release();
                return proxyMessage;
            }
        }
    }

}
